package points

import (
	"context"
	"encoding/json"
	"fmt"
	"net/url"
	"sale-admin/config"
	"sale-admin/config/redis"
	"sale-admin/internal/define"
	"strconv"
	"time"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/logx"
	"gorm.io/gorm"

	"bytes"
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"io"
	"log"
	"net/http"
	"sort"
	"strings"
)

const (

	// DEV
	ClientIDDev     = "dceb44f3c7ffb1508ee15ecb76c0a6bf"
	ClientSecretDev = "sgkiDyuxtAeuiD"

	// Domains
	MixcDomainTest = "https://test.mixcapp.com"
	MixcDomainProd = "https://app.mixcapp.com"
	Gateway        = "/gateway"

	// API endpoints
	DeductURL     = "/api/open/points/deduct"
	UserCancelURL = "/api/open/points/cancel"
	UserInfoURL   = "/api/open/members/currently_logged"

	// HTTP methods
	HTTPGet  = "GET"
	HTTPPost = "POST"
)

// MixcToken 结构体
type MixcToken struct {
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token"`
	SessionKey   string `json:"session_key"`
	ExpiresIn    int    `json:"expires_in"`
}

// MixcUserInfoResp 结构体
type MixcUserInfoResp struct {
	// 根据实际需要添加字段
}

// MixcBalance 结构体
type MixcBalance struct {
	// 根据实际需要添加字段
}

// MixcDeductBO 结构体
type MixcDeductBO struct {
	Code     string
	UserID   string
	MallCode string
	BizID    string
	Points   int
}

// MixcSignatureUtils - Struct representing the Mixc Signature Utilities
type MixcSignatureUtils struct{}

// SignType - Enum representing the signature types
type SignType int

const (
	// MD5 - MD5 signature type
	MD5 SignType = iota
	// HmacSHA256 - HmacSHA256 signature type
	HmacSHA256
)

// Sign - Function to generate the signature
func (m *MixcSignatureUtils) Sign(method, path string, headers, query, body map[string]string, signHeaderPrefixList []string, secret string, signType SignType) string {
	data := m.buildString(method, path, headers, query, body, signHeaderPrefixList)
	var digest string

	switch signType {
	case MD5:
		digest = m.md5Digest(data + secret)
	case HmacSHA256:
		digest = m.hmacSha256Digest(data, secret)
	default:
		fmt.Println("Signature Algorithm", signType, "not available")
	}

	return digest
}

func (m *MixcSignatureUtils) Sign2(method, path string, headers, query map[string]string,
	body map[string]interface{}, signHeaderPrefixList []string, secret string) (string, error) {
	if err := m.validateInputs(method, path, secret); err != nil {
		return "", err
	}
	data := m.buildString2(method, path, headers, query, body, signHeaderPrefixList)
	digest := m.hmacSha256Digest(data, secret)
	return digest, nil
}
func (m *MixcSignatureUtils) validateInputs(method, path, secret string) error {
	if method == "" {
		return errors.New("method cannot be empty")
	}
	if secret == "" {
		return errors.New("secret cannot be empty")
	}
	if path == "" {
		return errors.New("path cannot be empty")
	}
	return nil
}
func (m *MixcSignatureUtils) md5Digest(data string) string {
	return m.md5DigestAsHex(data)
}

func (m *MixcSignatureUtils) md5DigestAsHex(data string) string {
	hash := md5.New()
	hash.Write([]byte(data))
	return hex.EncodeToString(hash.Sum(nil))
}

func (m *MixcSignatureUtils) hmacSha256Digest(data string, secret string) string {
	key := []byte(secret)
	hmacSha256 := hmac.New(sha256.New, key)
	hmacSha256.Write([]byte(data))
	return hex.EncodeToString(hmacSha256.Sum(nil))
}

func (m *MixcSignatureUtils) buildString(method, path string, headers, query, body map[string]string, signHeaderPrefixList []string) string {
	var sb strings.Builder

	sb.WriteString(strings.ToUpper(method))
	sb.WriteString("\n")
	if headers != nil {
		sb.WriteString(headers["Accept"])
		sb.WriteString("\n")
		sb.WriteString(headers["Content-Type"])
		sb.WriteString("\n")
		headerStr := m.buildHeaders(headers, signHeaderPrefixList)
		resourceStr := m.buildResources(path, query, body)

		sb.WriteString(headerStr)
		sb.WriteString(resourceStr)
		fmt.Println("待签名信息:\n" + sb.String())
	}

	return sb.String()
}

func (m *MixcSignatureUtils) buildString2(method, path string, headers, query map[string]string,
	body map[string]interface{}, signHeaderPrefixList []string) string {
	var sb strings.Builder

	sb.WriteString(strings.ToUpper(method))
	sb.WriteString("\n")
	if headers != nil {
		sb.WriteString(headers["Accept"])
		sb.WriteString("\n")
		sb.WriteString(headers["Content-Type"])
		sb.WriteString("\n")
		headerStr := m.buildHeaders(headers, signHeaderPrefixList)
		resourceStr := m.buildResources2(path, query, body)

		sb.WriteString(headerStr)
		sb.WriteString(resourceStr)
		fmt.Println("待签名信息:\n" + sb.String())
	}

	return sb.String()
}

func (m *MixcSignatureUtils) buildHeaders(headers map[string]string, signHeaderPrefixList []string) string {
	var sb strings.Builder

	if headers != nil {
		sortedKeys := make([]string, 0, len(headers))
		for k := range headers {
			sortedKeys = append(sortedKeys, k)
		}
		sort.Strings(sortedKeys)

		var signHeadersStringBuilder strings.Builder

		for _, k := range sortedKeys {
			if m.isSignHeader(k, signHeaderPrefixList) {
				sb.WriteString(k)
				sb.WriteString(":")
				if v := headers[k]; v != "" {
					sb.WriteString(v)
				}
				sb.WriteString("\n")

				if signHeadersStringBuilder.Len() > 0 {
					signHeadersStringBuilder.WriteString(",")
				}
				signHeadersStringBuilder.WriteString(k)
			}
		}
		fmt.Println("待签名的头部字段:", signHeadersStringBuilder.String())
	}

	return sb.String()
}

func (m *MixcSignatureUtils) buildResources(path string, query, body map[string]string) string {
	var sb strings.Builder

	if path != "" {
		sb.WriteString(path)
	}

	sortedMap := make(map[string]string)
	for k, v := range query {
		sortedMap[k] = v
	}

	for k, v := range body {
		sortedMap[k] = v
	}
	// 按键排序构建参数字符串
	if len(sortedMap) > 0 {
		keys := make([]string, 0, len(sortedMap))
		for k := range sortedMap {
			keys = append(keys, k)
		}
		sort.Strings(keys)
		var sbParam strings.Builder

		for i, k := range keys {
			if k != "" {
				if i > 0 {
					sbParam.WriteString("&")
				}
				sbParam.WriteString(k)
				if v := sortedMap[k]; v != "" {
					sbParam.WriteString("=" + v)
				}
			}
		}
		if sbParam.Len() > 0 {
			sb.WriteString("?" + sbParam.String())
		}
	}
	return sb.String()
}

// 修改 buildResources 方法
func (m *MixcSignatureUtils) buildResources2(path string, query map[string]string,
	body map[string]interface{}) string {
	var sb strings.Builder

	if path != "" {
		sb.WriteString(path)
	}

	// 创建一个map来存储所有参数
	params := make(map[string]string)

	// 添加query参数
	for k, v := range query {
		params[k] = v
	}

	// 处理body参数
	for k, v := range body {
		params[k] = m.convertToString2(v)
	}

	// 按键排序构建参数字符串
	if len(params) > 0 {
		keys := make([]string, 0, len(params))
		for k := range params {
			keys = append(keys, k)
		}
		sort.Strings(keys)

		var sbParam strings.Builder
		for i, k := range keys {
			if k != "" {
				if i > 0 {
					sbParam.WriteString("&")
				}
				sbParam.WriteString(k)
				if v := params[k]; v != "" {
					sbParam.WriteString("=" + v)
				}
			}
		}
		if sbParam.Len() > 0 {
			sb.WriteString("?" + sbParam.String())
		}
	}

	return sb.String()
}

// 新增：处理interface{}类型转换为string的方法
func (m *MixcSignatureUtils) convertToString2(value interface{}) string {
	if value == nil {
		return ""
	}

	switch v := value.(type) {
	case string:
		return v
	case int:
		return strconv.Itoa(v)
	case int64:
		return strconv.FormatInt(v, 10)
	case float64:
		return strconv.FormatFloat(v, 'f', -1, 64)
	case bool:
		return strconv.FormatBool(v)
	case []interface{}:
		// 处理数组类型，转换为JSON字符串
		if bytes, err := json.Marshal(v); err == nil {
			return string(bytes)
		}
		return ""
	case map[string]interface{}:
		// 处理嵌套的map类型，转换为JSON字符串
		if bytes, err := json.Marshal(v); err == nil {
			return string(bytes)
		}
		return ""
	default:
		// 其他类型尝试JSON序列化
		if bytes, err := json.Marshal(v); err == nil {
			return string(bytes)
		}
		return fmt.Sprintf("%v", v)
	}
}

func (m *MixcSignatureUtils) isSignHeader(headerName string, signHeaderPrefixList []string) bool {
	if headerName == "" || strings.ToLower(headerName) == "x-ca-signature" {
		return false
	}

	if strings.HasPrefix(strings.ToLower(headerName), "x-ca-") {
		return true
	}

	if signHeaderPrefixList != nil {
		for _, prefix := range signHeaderPrefixList {
			if strings.ToLower(headerName) == prefix {
				return true
			}
		}
	}

	return false
}

const (
	USER_INFO_PATH      = "/api/open/members/currently_logged"
	POINTS_CONSUME_PATH = "/api/open/points/deduct"
	POINTS_REVERSE_PATH = "/api/open/points/cancel"
	POINTS_QUERY_PATH   = "/api/open/points/balance"
)

type WanxiangPoints struct {
	PointsInterface
}

func (wxp WanxiangPoints) secretInfo(ctx context.Context, openid string) (accessSession string, sessionKey string) {
	rdb := redis.NewDB()

	accessSession, _ = rdb.Get(ctx, define.WanxiangPointsAccessToken+openid).Result()
	sessionKey, _ = rdb.Get(ctx, define.WanxiangPointsSessionKey+openid).Result()
	return accessSession, sessionKey
}

// method 请求方式 GET POST
// path 请求路径
func (wxp WanxiangPoints) BuildHeader(accessToken, sessionKey, method, path string, query, body map[string]string) (
	headers map[string]string,
) {
	timestamp := time.Now().UnixMilli() // 毫秒时间戳
	// timestamp = 1742373129760
	nonce := fmt.Sprint(timestamp / 1000) // 请求的唯一标识
	// timestamp := System.currentTimeMillis();
	// nonce := fmt.Sprint(timestamp / 1000)         // 请设置本次请求的唯一标识，请根据业务自行设置并替换

	headers = map[string]string{
		"Accept":              "application/json",
		"Content-Type":        "application/json",
		"Authorization":       "bearer " + accessToken,
		"x-ca-nonce":          nonce,
		"x-ca-signature-type": "HmacSHA256",
		"x-ca-timestamp":      fmt.Sprint(timestamp),
	}

	// encoded := (&MixcSignatureUtils{}).Sign(method, path, headers, query, body, []string{}, sessionKey, HmacSHA256)

	customHeadersToSignPrefix := []string{}
	var m MixcSignatureUtils
	encoded := m.Sign(method, path, headers, query, body, customHeadersToSignPrefix, sessionKey, HmacSHA256)

	headers["x-ca-signature"] = encoded

	logx.Info(context.Background(), "BuildHeader", logx.Any("method", method))
	logx.Info(context.Background(), "BuildHeader", logx.Any("path", path))
	logx.Info(context.Background(), "BuildHeader", logx.Any("Authorization", "Bearer "+accessToken))
	logx.Info(context.Background(), "BuildHeader", logx.Any("x-ca-timestamp", fmt.Sprint(timestamp)))
	logx.Info(context.Background(), "BuildHeader", logx.Any("x-ca-nonce", nonce))
	logx.Info(context.Background(), "BuildHeader", logx.Any("x-ca-signature", encoded))
	return headers
}

func (wxp WanxiangPoints) BuildHeader2(accessToken, sessionKey, method, path string, query map[string]string, body map[string]interface{}) (
	headers map[string]string,
) {
	timestamp := time.Now().UnixMilli()   // 毫秒时间戳
	nonce := fmt.Sprint(timestamp / 1000) // 请求的唯一标识
	// timestamp := System.currentTimeMillis();
	// nonce := fmt.Sprint(timestamp / 1000)         // 请设置本次请求的唯一标识，请根据业务自行设置并替换

	headers = map[string]string{
		"Accept":              "application/json",
		"Content-Type":        "application/json",
		"Authorization":       "bearer " + accessToken,
		"x-ca-nonce":          nonce,
		"x-ca-signature-type": "HmacSHA256",
		"x-ca-timestamp":      fmt.Sprint(timestamp),
	}

	// encoded := (&MixcSignatureUtils{}).Sign(method, path, headers, query, body, []string{}, sessionKey, HmacSHA256)

	customHeadersToSignPrefix := []string{}
	var m MixcSignatureUtils
	encoded, _ := m.Sign2(method, path, headers, query, body, customHeadersToSignPrefix, sessionKey)

	headers["x-ca-signature"] = encoded

	logx.Info(context.Background(), "BuildHeader2", logx.Any("method", method))
	logx.Info(context.Background(), "BuildHeader2", logx.Any("path", path))
	logx.Info(context.Background(), "BuildHeader2", logx.Any("Authorization", "Bearer "+accessToken))
	logx.Info(context.Background(), "BuildHeader2", logx.Any("x-ca-timestamp", fmt.Sprint(timestamp)))
	logx.Info(context.Background(), "BuildHeader2", logx.Any("x-ca-nonce", nonce))
	logx.Info(context.Background(), "BuildHeader2", logx.Any("x-ca-signature", encoded))
	return headers
}
func NewWanxiangPoints() PointsInterface {
	return &WanxiangPoints{}
}

// 会员注册[不实现]
func (wxp WanxiangPoints) MemberRegist(ctx context.Context, db *gorm.DB, SalesID, mallID, phone, name string,
	gender int, birthday, idCard, Openid, headImg, provinceId, cityId, areaId, address string) (err error) {
	return nil
}

// 会员查询
func (wxp WanxiangPoints) GetMemberInfo(ctx context.Context, db *gorm.DB, SalesID, phone, openid string) (res MemberMsg, err error) {

	client := createHTTPClient()
	logx.Info(context.Background(), "GetMemberInfo", logx.Any("openid", openid))
	accessToken, sessionKey := wxp.secretInfo(ctx, openid) // todo
	logx.Info(context.Background(), "GetMemberInfo", logx.Any("accessToken", accessToken))
	logx.Info(context.Background(), "GetMemberInfo", logx.Any("sessionKey", sessionKey))

	logx.Info(context.Background(), "GetMemberInfo", logx.Any("config.Config.WanxiangPoints.BaseURL+USER_INFO_PATH", config.Config.WanxiangPoints.BaseURL+USER_INFO_PATH))
	header := wxp.BuildHeader(accessToken, sessionKey, "GET", USER_INFO_PATH, map[string]string{}, map[string]string{})
	// statusCode, bytes, err := helper.Net{}.Request(ctx, "GET", config.Config.WanxiangPoints.BaseURL+USER_INFO_PATH, header, nil)
	// logx.Info(context.Background(), "GetMemberInfo", logx.Any("statusCode", fmt.Sprint(statusCode)))
	// logx.Info(context.Background(), "GetMemberInfo", logx.Any("bytes", bytes))

	req, err := http.NewRequest(HTTPGet, config.Config.WanxiangPoints.BaseURL+USER_INFO_PATH, nil)
	if err != nil {
		// return fmt.Errorf("创建请求失败: %v", err)
		return
	}

	setHeadersRaw(req, header)

	resp, err := client.Do(req)
	if err != nil {
		// return fmt.Errorf("请求失败: %v", err)
		return
	}
	defer resp.Body.Close()

	// 读取响应体
	respBodyBytes, err := io.ReadAll(resp.Body)

	logx.Info(context.Background(), "GetMemberInfo", logx.Any("respBodyBytes", string(respBodyBytes)))

	// 重新创建响应体供JSON解码使用
	resp.Body = io.NopCloser(bytes.NewBuffer(respBodyBytes))

	var rsp WxMemberInfoRsp
	// err = json.Unmarshal(bytes, &rsp2)

	err = json.NewDecoder(resp.Body).Decode(&rsp)
	if err != nil {
		// return fmt.Errorf("解析响应失败: %v", err)
		return
	}

	// err = json.Unmarshal(bytes, &rsp)

	logx.Info(context.Background(), "GetMemberInfo", logx.Any("Code", fmt.Sprint(rsp.Code)))
	logx.Info(context.Background(), "GetMemberInfo", logx.Any("Message", rsp.Message))

	// if statusCode != 200 || err != nil {
	// 	// 错误返回
	// 	return
	// }

	if err != nil {
		// 错误返回
		return
	}
	logx.Info(context.Background(), "GetMemberInfo", logx.Any("rsp.Data.OpenID", rsp.Data.OpenID))
	logx.Info(context.Background(), "GetMemberInfo", logx.Any("rsp.Data.NickName", rsp.Data.NickName))
	logx.Info(context.Background(), "GetMemberInfo", logx.Any("rsp.Data.Avatar", rsp.Data.Avatar))
	logx.Info(context.Background(), "GetMemberInfo", logx.Any("rsp.Data.MallCode", rsp.Data.MallCode))
	logx.Info(context.Background(), "GetMemberInfo", logx.Any("rsp.Data.UnionID", rsp.Data.UnionID))
	logx.Info(context.Background(), "GetMemberInfo", logx.Any("rsp.Data.CardLevel", rsp.Data.CardLevel))
	logx.Info(context.Background(), "GetMemberInfo", logx.Any("rsp.Data.MemberID", rsp.Data.MemberID))
	logx.Info(context.Background(), "GetMemberInfo", logx.Any("rsp.Data.ErpMemberID", rsp.Data.ErpMemberID))

	// 处理用户信息
	res.NickName = rsp.Data.NickName

	res.ID = rsp.Data.MemberID
	res.CardNo = rsp.Data.MemberID
	res.UserToken = rsp.Data.OpenID

	//------------------------------------------------------------------------------------
	var URL url.URL
	query := URL.Query()
	queryMap := map[string]string{
		"mallCode": "2XRY00201",
		"source":   "大道智创应用",
	}
	if len(queryMap) > 0 {
		for key, val := range queryMap {
			query.Add(key, val)
		}
	}

	header = wxp.BuildHeader(accessToken, sessionKey, "GET", POINTS_QUERY_PATH, queryMap, map[string]string{})
	// statusCode, bytes, err = helper.Net{}.Request(ctx, "GET", config.Config.WanxiangPoints.BaseURL+POINTS_QUERY_PATH+"?"+query.Encode(), header, nil)

	req, err = http.NewRequest(HTTPGet, config.Config.WanxiangPoints.BaseURL+POINTS_QUERY_PATH+"?"+query.Encode(), nil)
	if err != nil {
		// return fmt.Errorf("创建请求失败: %v", err)
		return
	}

	setHeadersRaw(req, header)

	resp, err = client.Do(req)
	if err != nil {
		// return fmt.Errorf("请求失败: %v", err)
		return
	}
	defer resp.Body.Close()

	// 读取响应体
	respBodyBytes, err = io.ReadAll(resp.Body)

	logx.Info(context.Background(), "GetMemberInfo", logx.Any("respBodyBytes", string(respBodyBytes)))

	// 重新创建响应体供JSON解码使用
	resp.Body = io.NopCloser(bytes.NewBuffer(respBodyBytes))

	var rsp2 WxPointsInfoRsp
	// err = json.Unmarshal(bytes, &rsp2)

	err = json.NewDecoder(resp.Body).Decode(&rsp2)
	if err != nil {
		// return fmt.Errorf("解析响应失败: %v", err)
		return
	}

	// logx.Info(context.Background(), "GetMemberInfo", logx.Any("statusCode", fmt.Sprint(statusCode)))
	// logx.Info(context.Background(), "GetMemberInfo", logx.Any("Code", fmt.Sprint(rsp2.Code)))
	// logx.Info(context.Background(), "GetMemberInfo", logx.Any("Message", rsp2.Message))

	// if statusCode != 200 || err != nil {
	// 	// 错误返回
	// 	return
	// }
	if err != nil {
		// 错误返回
		return
	}
	if rsp2.Code != 0 {
		return
	}
	var points = 0.0
	points, _ = strconv.ParseFloat(rsp2.Data.AvailablePoints, 64)

	logx.Info(context.Background(), "GetMemberInfo", logx.Any("rsp2.Data.AvailablePoints", rsp2.Data.AvailablePoints))
	res.Points = points

	// queryMap = make(map[string]string)

	// params := make(map[string]string)
	// params["mallCode"] = "2XRY00201"       // 项目编号
	// params["bizId"] = "12345678"           // 业务ID或交易流水号（要求全局唯一，最大不超过50个字符）
	// params["bizType"] = "o706"          // 业务类型：(o706-第三方扣减)
	// params["value"] = 1                // tradeAmount // 扣减积分值 // 签名和传参类型不同
	// params["remarks"] = "大道智创小程序订单积分扣减" // 备注

	// header = wxp.BuildHeader(accessToken, sessionKey, "POST", POINTS_CONSUME_PATH, queryMap, params)

	// statusCode, bytes, err = helper.Net{}.Request(ctx, "POST", config.Config.WanxiangPoints.BaseURL+POINTS_CONSUME_PATH, header, nil)

	// logx.Info(context.Background(), "GetMemberInfo PointsConsume", logx.Any("statusCode", fmt.Sprint(statusCode)))
	// if statusCode != 200 || err != nil {
	// 	// 错误返回
	// 	return
	// }

	// err = json.Unmarshal(bytes, &rsp)

	// logx.Info(context.Background(), "GetMemberInfo PointsConsume", logx.Any("Code", fmt.Sprint(rsp.Code) ))
	// logx.Info(context.Background(), "GetMemberInfo PointsConsume", logx.Any("Message", rsp.Message ))

	return
}

func setHeadersRaw(req *http.Request, headers map[string]string) {
	// 创建新的header map
	req.Header = make(http.Header)

	// 使用底层map直接设置，避免标准化处理
	rawMap := map[string][]string(req.Header)
	for k, v := range headers {
		rawMap[k] = []string{v}
	}
}

// LoggingRoundTripper 用于记录HTTP请求和响应的详细信息
type LoggingRoundTripper struct {
	wrapped http.RoundTripper
}

// 记录请求和响应的详细结构
type HTTPLog struct {
	StartTime      time.Time
	Duration       time.Duration
	RequestMethod  string
	RequestURL     string
	RequestHeaders http.Header
	RequestBody    string
	StatusCode     int
	ResponseSize   int64
	ResponseBody   string
}

func (l *LoggingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
	// 开始计时
	startTime := time.Now()

	// 记录请求信息
	httpLog := &HTTPLog{
		StartTime:      startTime,
		RequestMethod:  req.Method,
		RequestURL:     req.URL.String(),
		RequestHeaders: req.Header,
	}

	// 记录请求体
	if req.Body != nil {
		bodyBytes, _ := io.ReadAll(req.Body)
		req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) // 恢复请求体
		httpLog.RequestBody = string(bodyBytes)
	}

	// 打印请求详情
	log.Printf("\n=== HTTP Request ===\n"+
		"Time: %v\n"+
		"Method: %s\n"+
		"URL: %s\n"+
		"Headers:\n%s\n"+
		"Body: %s\n",
		startTime.Format(time.RFC3339),
		httpLog.RequestMethod,
		httpLog.RequestURL,
		formatHeaders(httpLog.RequestHeaders),
		httpLog.RequestBody)

	// 执行实际的请求
	resp, err := l.wrapped.RoundTrip(req)
	if err != nil {
		log.Printf("HTTP Request failed: %v", err)
		return nil, err
	}

	// 记录响应信息
	httpLog.StatusCode = resp.StatusCode
	httpLog.Duration = time.Since(startTime)

	// 读取并记录响应体
	if resp.Body != nil {
		bodyBytes, _ := io.ReadAll(resp.Body)
		resp.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) // 恢复响应体
		httpLog.ResponseBody = string(bodyBytes)
		httpLog.ResponseSize = int64(len(bodyBytes))
	}

	// 打印响应详情
	log.Printf("\n=== HTTP Response ===\n"+
		"Duration: %v\n"+
		"Status: %d\n"+
		"Headers:\n%s\n"+
		"Body: %s\n",
		httpLog.Duration,
		httpLog.StatusCode,
		formatHeaders(resp.Header),
		httpLog.ResponseBody)

	return resp, nil
}

// formatHeaders 格式化HTTP头信息
func formatHeaders(headers http.Header) string {
	var builder strings.Builder
	for key, values := range headers {
		builder.WriteString(fmt.Sprintf("  %s: %s\n", key, strings.Join(values, ", ")))
	}
	return builder.String()
}

// createHTTPClient 创建带有详细日志记录的HTTP客户端
func createHTTPClient() *http.Client {
	return &http.Client{
		Timeout: 30 * time.Second,
		Transport: &LoggingRoundTripper{
			wrapped: http.DefaultTransport,
		},
	}
}

// 会员积分使用
func (wxp WanxiangPoints) PointsConsume(ctx context.Context, db *gorm.DB, salesID, openid, orderID string,
	tradeAmount float64, mallCode string) (err error) {

	logx.Info(context.Background(), "PointsConsume", logx.Any("salesID", salesID))
	logx.Info(context.Background(), "PointsConsume", logx.Any("openid", openid))
	logx.Info(context.Background(), "PointsConsume", logx.Any("orderID", orderID))
	logx.Info(context.Background(), "PointsConsume", logx.Any("mallCode", mallCode))
	logx.Info(context.Background(), "PointsConsume", logx.Any("tradeAmount", fmt.Sprint(tradeAmount)))
	accessToken, sessionKey := wxp.secretInfo(ctx, openid)

	queryMap := make(map[string]string)

	// params := make(map[string]string)
	// params["mallCode"] = mallCode       // 项目编号
	// params["bizId"] = orderID           // 业务ID或交易流水号（要求全局唯一，最大不超过50个字符）
	// params["bizType"] = "o706"          // 业务类型：(o706-第三方扣减)
	// params["value"] = int(tradeAmount)           // tradeAmount // 扣减积分值 // 签名和传参类型不同
	// params["remarks"] = "大道智创小程序订单积分扣减" // 备注

	body := map[string]interface{}{
		"mallCode": mallCode,
		"bizId":    orderID,
		"bizType":  "o706",
		"value":    fmt.Sprint(int(tradeAmount)),
		"remarks":  "大道智创小程序订单积分扣减",
	}

	header := wxp.BuildHeader2(accessToken, sessionKey, "POST", POINTS_CONSUME_PATH, queryMap, body)
	// statusCode, bytes, err := helper.Net{}.Request(ctx, "POST", config.Config.WanxiangPoints.BaseURL+POINTS_CONSUME_PATH, header, nil)

	// 将 body 转换为 JSON
	bodyBytes, err := json.Marshal(body)
	if err != nil {
		return fmt.Errorf("构建请求体失败: %v", err)
	}
	client := createHTTPClient()

	req, err := http.NewRequest(HTTPPost, config.Config.WanxiangPoints.BaseURL+POINTS_CONSUME_PATH, bytes.NewBuffer(bodyBytes))
	if err != nil {
		return fmt.Errorf("创建请求失败: %v", err)
	}

	setHeadersRaw(req, header)

	resp, err := client.Do(req)
	if err != nil {
		return fmt.Errorf("请求失败: %v", err)
	}
	defer resp.Body.Close()

	// 读取响应体
	respBodyBytes, err := io.ReadAll(resp.Body)

	logx.Info(context.Background(), "PointsConsume", logx.Any("respBodyBytes", string(respBodyBytes)))

	if err != nil {
		log.Printf("读取响应体失败: %v", err)
		return fmt.Errorf("读取响应体失败: %v", err)
	}

	// 记录原始响应
	log.Printf("pointDeduct原始响应: %s", string(respBodyBytes))
	// 重新创建响应体供JSON解码使用
	resp.Body = io.NopCloser(bytes.NewBuffer(respBodyBytes))

	var result *MixcUserInfoResp

	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return fmt.Errorf("解析响应失败: %v", err)
	}

	if result == nil {
		return fmt.Errorf("pointDeduct 失败")
	}
	// 记录日志
	log.Printf("pointDeduct 请求返回, result: %+v", result)

	// var rsp WxCommonRsp
	// err = json.Unmarshal(bytes, &rsp)

	// logx.Info(context.Background(), "PointsConsume", logx.Any("Code", fmt.Sprint(rsp.Code) ))
	// logx.Info(context.Background(), "PointsConsume", logx.Any("Message", rsp.Message ))
	// if err != nil {
	// 	// 错误返回
	// 	return
	// }
	// if rsp.Code != 0 {
	// 	return errorx.New(rsp.Message, rsp.Code)
	// }
	return
}

// 会员积分冲正
func (wxp WanxiangPoints) PointsReverse(ctx context.Context, db *gorm.DB, salesID, openid, refundOrderID, orderID string,
	tradeAmount float64, mallCode string) (err error) {

	logx.Info(context.Background(), "PointsReverse", logx.Any("openid", string(openid)))
	logx.Info(context.Background(), "PointsReverse", logx.Any("mallCode", string(mallCode)))
	logx.Info(context.Background(), "PointsReverse", logx.Any("tradeAmount", fmt.Sprint(tradeAmount)))

	// url := config.Config.WanxiangPoints.BaseURL + POINTS_REVERSE_PATH
	accessToken, sessionKey := wxp.secretInfo(ctx, openid)

	queryMap := make(map[string]string)

	// params := make(map[string]string)
	// params["mallCode"] = mallCode             // 项目编号
	// params["bizId"] = orderID                 // 业务ID或交易流水号（要求全局唯一，最大不超过50个字符）
	// params["bizType"] = "i706"                // 业务类型：(i706-第三方取消扣分)
	// params["value"] = fmt.Sprint(tradeAmount) // tradeAmount // 扣减积分值 // 签名和传参类型不同
	// params["remarks"] = "大道智创小程序订单积分冲正"       // 备注

	// header := wxp.BuildHeader(accessToken, sessionKey, "POST", POINTS_REVERSE_PATH, queryMap, params)
	// statusCode, bytes, err := helper.Net{}.Request(ctx, "POST", url, header, params)

	// var rsp WxCommonRsp
	// err = json.Unmarshal(bytes, &rsp)
	// if err != nil {
	// 	// 错误返回
	// 	return
	// }

	// logx.Info(context.Background(), "PointsReverse", logx.Any("statusCode", fmt.Sprint(statusCode)))
	// logx.Info(context.Background(), "PointsReverse", logx.Any(" rsp.Code", fmt.Sprint(rsp.Code)))
	// logx.Info(context.Background(), "PointsReverse", logx.Any(" rsp.Message", fmt.Sprint(rsp.Message)))
	// if statusCode != 200 || err != nil {
	// 	// 错误返回
	// 	return
	// }
	// if rsp.Code != 0 {
	// 	return errorx.New(rsp.Message, rsp.Code)
	// }
	// return

	body := map[string]interface{}{
		"mallCode": mallCode,
		"bizId":    orderID,
		"bizType":  "i706",
		"value":    fmt.Sprint(int(tradeAmount)),
		"remarks":  "大道智创小程序订单积分冲正",
	}

	header := wxp.BuildHeader2(accessToken, sessionKey, "POST", POINTS_REVERSE_PATH, queryMap, body)
	// statusCode, bytes, err := helper.Net{}.Request(ctx, "POST", config.Config.WanxiangPoints.BaseURL+POINTS_CONSUME_PATH, header, nil)

	// 将 body 转换为 JSON
	bodyBytes, err := json.Marshal(body)
	if err != nil {
		return fmt.Errorf("构建请求体失败: %v", err)
	}
	client := createHTTPClient()

	req, err := http.NewRequest(HTTPPost, config.Config.WanxiangPoints.BaseURL+POINTS_REVERSE_PATH, bytes.NewBuffer(bodyBytes))
	if err != nil {
		return fmt.Errorf("创建请求失败: %v", err)
	}

	setHeadersRaw(req, header)

	resp, err := client.Do(req)
	if err != nil {
		return fmt.Errorf("请求失败: %v", err)
	}
	defer resp.Body.Close()

	// 读取响应体
	respBodyBytes, err := io.ReadAll(resp.Body)

	logx.Info(context.Background(), "PointsReverse", logx.Any("respBodyBytes", string(respBodyBytes)))

	if err != nil {
		log.Printf("读取响应体失败: %v", err)
		return fmt.Errorf("读取响应体失败: %v", err)
	}

	return
}

// 会员积分查询
func (wxp WanxiangPoints) PointsQuery(ctx context.Context, salesID, openid, mallCode string) (points float64, err error) {
	accessToken, sessionKey := wxp.secretInfo(ctx, openid)

	// if accessToken == "" && sessionKey == "" {
	// 	accessToken = "00d40d7812f7497f8ee3124d55660ca9"
	// 	sessionKey = "XizMRU"
	// }

	client := createHTTPClient()

	logx.Info(context.Background(), "PointsQuery", logx.Any("openid", fmt.Sprint(openid)))
	logx.Info(context.Background(), "PointsQuery", logx.Any("accessToken", fmt.Sprint(accessToken)))
	logx.Info(context.Background(), "PointsQuery", logx.Any("sessionKey", fmt.Sprint(sessionKey)))
	logx.Info(context.Background(), "PointsQuery", logx.Any("mallCode", fmt.Sprint(mallCode)))
	var URL url.URL
	query := URL.Query()
	queryMap := map[string]string{
		"mallCode": "2XRY00201",
		"source":   "大道智创应用",
	}
	if len(queryMap) > 0 {
		for key, val := range queryMap {
			query.Add(key, val)
		}
	}

	header := wxp.BuildHeader(accessToken, sessionKey, "GET", POINTS_QUERY_PATH, queryMap, map[string]string{})
	// statusCode, bytes, err := helper.Net{}.Request(ctx, "GET", url+"?"+query.Encode(), header, nil)

	// logx.Info(context.Background(), "PointsQuery", logx.Any("statusCode", fmt.Sprint(statusCode)))
	// if statusCode != 200 || err != nil {
	// 	// 错误返回
	// 	return
	// }

	req, err := http.NewRequest(HTTPGet, config.Config.WanxiangPoints.BaseURL+POINTS_QUERY_PATH+"?"+query.Encode(), nil)
	if err != nil {
		// return fmt.Errorf("创建请求失败: %v", err)
		return
	}

	setHeadersRaw(req, header)

	resp, err := client.Do(req)
	if err != nil {
		// return fmt.Errorf("请求失败: %v", err)
		return
	}
	defer resp.Body.Close()

	// 读取响应体
	respBodyBytes, err := io.ReadAll(resp.Body)

	logx.Info(context.Background(), "PointsQuery", logx.Any("respBodyBytes", string(respBodyBytes)))

	// 重新创建响应体供JSON解码使用
	resp.Body = io.NopCloser(bytes.NewBuffer(respBodyBytes))

	var rsp WxPointsInfoRsp
	// err = json.Unmarshal(bytes, &rsp2)

	err = json.NewDecoder(resp.Body).Decode(&rsp)
	if err != nil {
		// return fmt.Errorf("解析响应失败: %v", err)
		return
	}

	// var rsp WxPointsInfoRsp
	// err = json.Unmarshal(bytes, &rsp)
	// logx.Info(context.Background(), "PointsQuery", logx.Any("rsp.Code", fmt.Sprint(rsp.Code)))
	// logx.Info(context.Background(), "PointsQuery", logx.Any("rsp.Message", fmt.Sprint(rsp.Message)))
	// logx.Info(context.Background(), "PointsQuery", logx.Any("rsp.Data.AvailablePoints", fmt.Sprint(rsp.Data.AvailablePoints)))
	// if err != nil {
	// 	// 错误返回
	// 	return
	// }
	if rsp.Code != 0 {
		return 0, errorx.New(rsp.Message, rsp.Code)
	}
	points, _ = strconv.ParseFloat(rsp.Data.AvailablePoints, 64)
	return points, nil
}
